package org.javahispano.javacup.tacticas_aceptadas.jcrosas.chuky.futbolista;

import java.util.ArrayList;

import org.javahispano.javacup.modelo.ComandoIrA;
import org.javahispano.javacup.modelo.Constantes;
import org.javahispano.javacup.tacticas_aceptadas.jcrosas.chuky.entrenador.Sugerencia;
import org.javahispano.javacup.tacticas_aceptadas.jcrosas.chuky.entrenador.VisionPartido;
import org.javahispano.javacup.tacticas_aceptadas.jcrosas.chuky.entrenador.Sugerencia.TipoSugerencia;
import org.javahispano.javacup.tacticas_aceptadas.jcrosas.chuky.futbolista.habilidad.*;
import org.javahispano.javacup.tacticas_aceptadas.jcrosas.chuky.util.PosicionCampo;
import org.javahispano.javacup.tacticas_aceptadas.jcrosas.chuky.util.PosicionFutura;

/**
 * @author Joan Crosas
 *
 */
public class Futbolista extends FutbolistaGenerico implements Comparable<Futbolista> {
	private final FutbolistaConfig config;
	private PosicionCampo posicion;
	private int iteracionesParaRematar;
	private ArrayList<Habilidad> habilidades;
	private JugadaMortalPreparacion habilidadPrepararJugadaMortal;
	
	private int seguridadPase;
	private double distanciaAvanzadaPase;

	private Oponente oponenteAsignado;
	private int zonaCubrirOponente;
	private int tiempoPresionDefensiva; 
	
	private double distanciaPorteriaRival;
	private PosicionCampo posicionJugada;
	private PosicionFutura posicionInterceptarBalon;
	
	/**
	 * 
	 */
	public Futbolista( FutbolistaConfig futbolistaConfig ) {
		config = futbolistaConfig;
		
		/*
		 * defino las habilidades del jugador por orden de importancia
		 */
		habilidades = new ArrayList<Habilidad>();
		habilidades.add( new Defender( this ) ); 
		habilidades.add( new JugadaPosicionDelanteros( this ) );
		habilidades.add( new InterceptarBalon( this ) ); 
		habilidades.add( new Gol( this ) );
		habilidades.add( new JugadaMortal( this ) );
		habilidades.add( new AvanzarConBalonRestrictivo( this ) );
		habilidades.add( new PaseOfensivo( this ) ); 
		habilidades.add( new Saque( this ) );
		habilidades.add( new PreparacionRegate( this ) );
		habilidades.add( new AvanzarConBalon( this ) ); 
		habilidades.add( new JugadaInExtremis( this ) );
		habilidades.add( new RetrocederConBalon( this ) ); 
		habilidades.add( new PaseDefensivo( this ) ); 
		habilidades.add( new GolInExtremis( this ) );
		habilidades.add( new Despeje( this ) );
		habilidadPrepararJugadaMortal = new JugadaMortalPreparacion( this );
		
		
		seguridadPase = config.getRol().getSeguridadPase();
		distanciaAvanzadaPase = config.getRol().getDistanciaAvanzadaPase();
		tiempoPresionDefensiva = 0;
		
		oponenteAsignado = null;
		zonaCubrirOponente = 0;
		
	}

	public void evaluar() {
		
		if( oponenteAsignado != null ) {
			tiempoPresionDefensiva = getTiempoPresionDefensiva( getVisionPartido().getBalon().getPosicionBalon(), oponenteAsignado.getPosicion() );
		}
		
		
		for( int i = 0; i < habilidades.size(); i++ ) {
			if( habilidades.get( i ).ejecutar() ) {
				break;
			}
		}
		
	}
	
	public void evaluar( Sugerencia sugerencia ) {
		if( sugerencia.getTipo() == Sugerencia.TipoSugerencia.CORRER ||
				sugerencia.getTipo() == Sugerencia.TipoSugerencia.POSICION_RECOMENDADA ) {
			PosicionFutura posicionIntercepcionBalon = puedoInterceptarBalon();
			if( posicionIntercepcionBalon != null ) {
				getVisionPartido().addComando( new ComandoIrA( getIndice(), posicionIntercepcionBalon.toPosicion() ) );
			} else {
				getVisionPartido().addComando( new ComandoIrA( getIndice(), sugerencia.getPosicionDestino().toPosicion() ) );
			}
			
		} else if( sugerencia.getTipo() == Sugerencia.TipoSugerencia.RECIBIR_PASE ) {
			// si la sugerencia es recibir un pase, miramos donde ir�
			PosicionFutura posicionIntercepcionBalon = puedoInterceptarPase( getVisionPartido().getBalon() );
			if( posicionIntercepcionBalon != null ) {
				getVisionPartido().addComando( new ComandoIrA( getIndice(), posicionIntercepcionBalon.toPosicion() ) );
			} else {
				getVisionPartido().addComando( new ComandoIrA( getIndice(), sugerencia.getPosicionDestino().toPosicion() ) );
			}
			
		} else if( sugerencia.getTipo() == Sugerencia.TipoSugerencia.REGATE ) {
			// si la sugerencia es regate, nos lo creemos ciegamente
			getVisionPartido().addComando( new ComandoIrA( getIndice(), sugerencia.getPosicionDestino().toPosicion() ) );
			
		} else if( sugerencia.isJugadaMortal() ) {
			if( !balonEncima( getVisionPartido().getBalon() ) ) {
				PosicionFutura posicionFutbolistaIntBalon = puedoInterceptarBalon();
				PosicionFutura posicionOponentesIntBalon = null;
				Oponente oponentePeligroso = getVisionPartido().oponentePuedeInterceptarBalon();
				if( oponentePeligroso != null ) {
					posicionOponentesIntBalon = oponentePeligroso.puedoInterceptarBalon();
				}
				if( posicionFutbolistaIntBalon != null && sugerencia.getPosicionDestino().distancia(posicionFutbolistaIntBalon) > 3.6 ) {
					posicionFutbolistaIntBalon = null;
				}
				
				if( posicionFutbolistaIntBalon != null && posicionOponentesIntBalon == null ) {
					getVisionPartido().addComando( new ComandoIrA( getIndice(), posicionFutbolistaIntBalon.toPosicion() ) );
					
				} else if( posicionFutbolistaIntBalon != null && posicionOponentesIntBalon != null ) {
					PosicionCampo posJugada = habilidadPrepararJugadaMortal.getPosicionJugadaFutbolista1( posicionOponentesIntBalon );
					if( sugerencia.getTipo() == TipoSugerencia.JUGADA_MORTAL_JUGADOR_2 ) {
						posJugada = habilidadPrepararJugadaMortal.getPosicionJugadaFutbolista2( posicionOponentesIntBalon );
					}
					getVisionPartido().addComando( new ComandoIrA( getIndice(), posJugada.toPosicion() ) );
					
				} else {
					getVisionPartido().addComando( new ComandoIrA( getIndice(), sugerencia.getPosicionDestino().toPosicion() ) );
				}
			}
		}
			
	}


	@Override
	public int compareTo( Futbolista futbolista ) {
		
		double resultado = futbolista.getImportancia() - this.getImportancia();
		if( resultado < 0.0 ) {
			return -1;
		} else if( resultado > 0.0 ) {
			return 1;
		}
		return 0;
	}
	
	public double potenciaMaxAutopase() {
		double distanciaJugador = 2 * Constantes.DISTANCIA_CONTROL_BALON + getVelocidad() * Constantes.ITERACIONES_GOLPEAR_BALON;
		
		double distanciaBalon = 1.0;
		for( int i = 0; i < Constantes.ITERACIONES_GOLPEAR_BALON; i++ ) {
			distanciaBalon += Math.pow( Constantes.FACTOR_DISMINUCION_VEL_BALON_SUELO, i );
		}
		distanciaBalon *= getRemate();
		
		return distanciaJugador / distanciaBalon;
	}
	
	public void disminuirRestriccionesPase() {
		if( seguridadPase > FutbolistaBase.SEGURIDAD_PASE_MIN ) seguridadPase--;
		if( distanciaAvanzadaPase > FutbolistaBase.DISTANCIA_AVANZADA_PASE_MIN ) distanciaAvanzadaPase -= 6;
	}
	
	public void resetRestriccionesPase() {
		seguridadPase = config.getRol().getSeguridadPase();
		distanciaAvanzadaPase = config.getRol().getDistanciaAvanzadaPase();
	}
	
	public boolean isRestriccionesPaseMinimas() {
		return seguridadPase <= FutbolistaBase.SEGURIDAD_PASE_MIN && distanciaAvanzadaPase <= FutbolistaBase.DISTANCIA_AVANZADA_PASE_MIN;
	}
	
	
	public PosicionCampo getPosicionJugada() {
		return posicionJugada;
	}
	
	public PosicionCampo getPosicionBaseDefensiva() {
		PosicionCampo posDef = getPosicionJugada();
		double angulo = posDef.angulo( posicion );
		double distancia = posDef.distancia( posicion ) / 2;
		posDef = posDef.moverAngulo( angulo, distancia );
		return posDef;
	}
	
	private int getTiempoPresionDefensiva( PosicionCampo inicial, PosicionCampo fin ) {
		double distanciaTotal = inicial.distancia( fin );
		double velocidad = Constantes.getVelocidadRemate( 1 ); // velocidad maxima de remate
		double distancia = velocidad * 4;
		int t = 0;
		while( distancia < distanciaTotal && t < FutbolistaBase.TIEMPO_MAX_PRESION_DEFENSIVA ) {
			velocidad *= Constantes.FACTOR_DISMINUCION_VEL_BALON_AIRE;
			distancia += velocidad * 3;
			t++;			
		}
		return t;
	}

	
	public void setPosicion( PosicionCampo posicion ) {
		this.posicion =  posicion;
		posicionInterceptarBalon = puedoInterceptar( getVisionPartido().getBalon() );
		distanciaPorteriaRival = posicion.distancia( POSICION_PORTERIA_RIVAL );
		
		double angulo = config.getPosicionDefensiva().angulo( config.getPosicionOfensiva() );
		double d = config.getPosicionOfensiva().distancia( config.getPosicionDefensiva() );
		d = d * getVisionPartido().getAtaque();
		posicionJugada = config.getPosicionDefensiva().moverAngulo( angulo, d );	
	}
	
	@Override
	public int getIndice() {
		return config.getIndice();
	}
	
	@Override
	public int getNumero() {
		return config.getNumero();
	}

	@Override
	public PosicionCampo getPosicion() {
		return posicion;
	}

	@Override
	public Rol getRol() {
		return config.getRol();
	}

	@Override
	public double getVelocidad() {
		return config.getVelocidad();
	}

	@Override
	public double getRemate() {
		return config.getRemate();
	}
	
	public VisionPartido getVisionPartido() {
		return config.getVisionPartido();
	}
	
	public double getImportancia() {
		return config.getImportancia();
	}
	
	@Override
	public double getPrecision() {
		return config.getPrecision();
	}
	
	
	@Override
	public int getIteracionesParaRematar() {
		return iteracionesParaRematar;
	}
	
	public void setIteracionesParaRematar( int iteracionesParaRematar ) {
		this.iteracionesParaRematar = iteracionesParaRematar;
	}

	public int getSeguridadPase() {
		return seguridadPase;
	}

	public double getDistanciaAvanzadaPase() {
		return distanciaAvanzadaPase;
	}

	public Oponente getOponenteAsignado() {
		return oponenteAsignado;
	}

	public void asignarOponente( Oponente oponenteAsignado, int zonaCubrirOponente ) {
		this.oponenteAsignado = oponenteAsignado;
		this.zonaCubrirOponente = zonaCubrirOponente;
	}
	
	public int getZonaCubrirOponente() {
		return zonaCubrirOponente;
	}

	public int getTiempoPresionDefensiva() {
		return tiempoPresionDefensiva;
	}

	public double getDistanciaPorteriaRival() {
		return distanciaPorteriaRival;
	}
	
	public double getAnguloPorteria() {
		return posicion.angulo( POSICION_PORTERIA );
	}
	
	public double getAnguloPorteriaRival() {
		return posicion.angulo( FutbolistaBase.POSICION_PORTERIA_RIVAL );
	}

	public PosicionFutura puedoInterceptarBalon() {
		return posicionInterceptarBalon;
	}
	
	public void resetPuedoInterceptarBalon() {
		posicionInterceptarBalon = null;
	}
	
	public void prepararJugadaMortal() {
		habilidadPrepararJugadaMortal.ejecutar();
	}

}
